<?php


namespace App\Models\CacheModel;


use app\common\lib\Aes;
use app\common\lib\exception\ApiException;
use app\common\lib\Util;
use App\Models\Api\BaseCache;
use App\Models\Api\Recode;
use Exception;
use think\Log;
use AstroTool\Cache\CacheManage;

/**
 * 用户钱包
 * Class ZhunleUserAccount
 * @package App\Models\CacheModel
 */
class ZhunleUserAccount extends BaseCache
{
    protected $table = 'wechat_backup_07_18_14_43_00.zhunle_user_account';
    protected $cacheModel = 'user.coin';

    /**
     * 充值准币
     * @param int $uid
     * @param array $data
     * @return bool|int|string
     * @throws Exception
     */
    public function SaveData($uid, $data)
    {
        try
        {
            $id = $this->insertGetId($data);
        }
        catch (Exception $e)
        {
            Log::write($uid . '用户充值余额数量失败：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】');
            return false;
        }
        CacheManage::getInstance()->setCacheConfig($this->cacheModel, $uid)->rmCache();
        return $id;
    }

    /**
     * 更新用户准币数量
     * @param int $uid
     * @param array $data
     * @param array $where
     * @return bool|int|string
     * @throws Exception
     */
    public function UpdateData($uid, $data, $where)
    {
        try
        {
            $this->where($where)->update($data);
        }
        catch (Exception $e)
        {
            Log::write($uid . '更新用户余额数量失败：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】');
            return false;
        }
        CacheManage::getInstance()->setCacheConfig($this->cacheModel, $uid)->rmCache();
        return true;
    }

    /**
     * 准币退款
     * @param $uid
     * @param $orders
     * @param $refundPrice
     * @param int $consumer_type
     * @param int $liveRecordId
     * @throws Exception
     */
    public function refund($uid, $orders, $refundPrice, $consumer_type, $transactionId = '', $liveRecordId = 0)
    {
        OrdersLib::UpdateCoin($orders['order_id'], $orders['order_type'], $refundPrice, $uid, $consumer_type);
        $user_coin = OrdersLib::getCoinNum($uid);
        $coin_num = OrdersLib::getOrderCoinNum($refundPrice);
        $extend = [];
        if (isset($orders['extend']) && $orders['extend'])
        {
            $extendData = json_decode($orders['extend'], true);
            if (isset($extendData['live_info']))
            {   // 直播间订单  退款写入直播间信息
                $extend = [
                    'live_info' => [
                        'live_id' => $extendData['live_info']['live_id'],
                        'name' => $extendData['live_info']['name'],
                        'avatar' => $extendData['live_info']['avatar'],
                        'live_record_id' => $liveRecordId,
                    ],
                ];
            }
        }

        $res = [
            'status' => 1,
            'account' => 0,
            'uid' => $uid,
            'consumer_type' => $consumer_type,
            'order_type' => $orders['order_type'],
            'gid' => $orders['gid'],
            'pray_date' => 0,
            'rid' => 0,
            'total_amount' => $refundPrice,
            'coin_num' => $coin_num,
            'balance' => $user_coin,
            'order_id' => $orders['order_id'],
            'transaction_id' => $transactionId,
            'trade_type' => 4,
            'create_time' => time(),
            'extend' => json_encode($extend),
        ];
        //增加准币明细记录
        (new ZhunleUserAccountRecord())->SaveData($uid, $res);
    }

    /**
     * 获取用户准币
     * @param $uid
     * @return array|bool|mixed|string
     * @throws Exception
     */
    public function getUserCoinFromCache($uid)
    {
        $data = CacheManage::getInstance()->setCacheConfig($this->cacheModel, $uid)->getDataAndSet(function () use ($uid)
        {
            return $this->getUserCoinFromDms($uid);
        });
        //若用户无准币数据则生成
        if (!$data)
        {
            $data = [
                'uid' => (int)$uid,
                'status' => 1,
                'balance' => 0,
                'total_amount' => 0,
                'consume_price' => 0,
                'total_coin' => 0,
                'consume_coin' => 0,
                'last_time' => 0,
                'create_time' => time(),
                'update_time' => 0,
                'password' => '',
                'set_password_time' => 0,
            ];
            $this->SaveData($uid, $data);
            CacheManage::getInstance()->setCacheConfig($this->cacheModel, $uid)->setCache($data);
        }
        $data = arrayKeyData2int($data, ['id', 'uid', 'status', 'total_coin', 'balance', 'consume_coin', 'last_time', 'create_time', 'update_time', 'set_password_time']);

        return $data;
    }

    /**
     * 数据库获取用户准币
     * @param int $uid
     * @return array
     */
    public function getUserCoinFromDms($uid)
    {
        try
        {
            $data = $this->field('id,uid,status,password,set_password_time,balance,total_amount,consume_price,total_coin,consume_coin')->where(['uid' => $uid])->findOrFail()->toArray();
            if ($data['status'] === 2)
            {
                throw new ApiException('当前账户钱包已被冻结');
            }
        }
        catch (Exception $e)
        {
            $data = [];
        }
        return $data;
    }

    /**
     * 准币支付验证
     * @param array $userCoinInfo 用户准币账户信息
     * @param string $password 输入的准币密码  $isLive=true（直播的话），那么 前端传过来的就是md5后的
     * @param string $goodsCoin 商品准币价格
     * @param bool $isLive 前端取消按钮，展示类型：true：取消；false：切换其他支付方式
     * @param bool $verifyPassword 是否需要验证密码
     * @throws ApiException
     */
    public function verifyCoinPay($userCoinInfo, $password, $goodsCoin, $isLive = false, $verifyPassword = true)
    {
        $user_coin = (int)($userCoinInfo['balance'] ?? 0);// 准币余额
        if ($verifyPassword === true)
        {
            if (!$userCoinInfo['password'] && (!Util::IsIos() || (Util::IsIos() && Util::CheckAppVersion('2.9.11') === '小')))
            {
                if ($isLive)
                {
                    throw new ApiException('支付密码未设置', 200, 423);
                }
                throw new ApiException('支付密码未设置', 200, 420);
            }

            if (!$password)
            {
                //IOS准币可支持无密码
                if (Util::IsIos() && Util::CheckAppVersion('2.9.11') !== '小')
                {
                    $coinPassword = '';
                } else
                {
                    throw new ApiException('请输入密码', 200, 0);
                }
            } else
            {
                if (Util::getAccountResidualErrorNum($userCoinInfo['uid'], 1) <= 0)
                {
                    $msg = "今日密码错误次数达到上限\r\n每日最多可尝试5次密码输入";
                    throw new ApiException($msg, 200, 421);
                }

                if (Util::CheckAppVersion('2.7.6') !== '小')
                {
                    $type = request()->header('app-type') === 'harmonyos' ? 'harmonyos' : 'app';
                    $coinPasswordData = (new Aes())->decryptWithOpenssl($password, $type);
                    $password = $coinPasswordData && mb_strlen($coinPasswordData) >= 6 ? mb_substr($coinPasswordData, 0, 6) : '';
                    if ($isLive)
                    {
                        $password = md5($password);
                    }
                }

                if ($isLive)
                {
                    $coinPassword = md5($password . $userCoinInfo['uid']);
                } else
                {
                    $coinPassword = md5(md5($password) . $userCoinInfo['uid']);
                }
            }

            if ($coinPassword !== $userCoinInfo['password'])
            {
                $res = Util::getAccountResidualErrorNum($userCoinInfo['uid'], 2);
                if ($res > 0)
                {
                    $msg = "密码输入错误，剩余{$res}次尝试机会";
                    throw new ApiException($msg, 200, 0);
                }
                $msg = "今日密码错误次数达到上限\r\n每日最多可尝试5次密码输入";
                throw new ApiException($msg, 200, 421);
            }
        }

        //检测余额是否足够
        if ($user_coin < $goodsCoin)
        {
            throw new ApiException('准币不足，请前去充值', 200, 410);
        }
    }

    /**
     * 准币账户信息更新(充值时需获取明细里的准币数,不可直接金额计算准币数,因内部测试金额是一分钱)
     * @param $uid
     * @param int $consumer_type 准币变更类型
     * @param array $records 明细记录
     * @param int $coin_num 准币数
     * @param int $trade_type 支付类型
     * @param string $transactionId
     * @throws Exception
     */
    public function updateCoinInfo($uid, $consumer_type, $records, $coin_num, $trade_type = 0, $transactionId = '')
    {
        $total_amount = OrdersLib::getOrderCoinTotalAmount($coin_num);
        //获取用户钱包信息
        $userCoin = $this->getUserCoinFromCache($uid);
        switch ($consumer_type)
        {
            case 1://充值
            case 3://赠送
            case 4://准币购买商品退款
                $balance = $userCoin['balance'] + $coin_num;
                $coinUpdate = ['balance' => $balance, 'update_time' => time()];
                if ($consumer_type == 1)
                {
                    $coinUpdate['total_amount'] = $userCoin['total_amount'] + $total_amount;
                    $coinUpdate['total_coin'] = $userCoin['total_coin'] + $coin_num;
                }
                //更新用户钱包金额
                $this->UpdateData($uid, $coinUpdate, ['uid' => $uid]);
                break;
            case 2://消费
            case 5://打赏
                $balance = $userCoin['balance'] - $coin_num;
                $consume_price = $userCoin['consume_price'] + $total_amount;
                $consume_coin = $userCoin['consume_coin'] + $coin_num;
                //更新用户钱包金额
                $this->UpdateData($uid, ['balance' => $balance, 'consume_price' => $consume_price, 'consume_coin' => $consume_coin, 'update_time' => time()], ['uid' => $uid]);
                break;
            case 6://准币充值退款
                $balance = $userCoin['balance'] - $coin_num;
                $total_amount = $userCoin['total_amount'] - $total_amount;
                $total_coin = $userCoin['total_coin'] - $coin_num;
                //更新用户钱包金额
                $this->UpdateData($uid, ['balance' => $balance, 'total_amount' => $total_amount, 'total_coin' => $total_coin, 'update_time' => time()], ['uid' => $uid]);
                break;
        }
        //更新用户准币明细状态
        $recordData = ['status' => 1, 'update_time' => time()];
        if ($trade_type)
        {
            $recordData['trade_type'] = $trade_type;
        }
        if ($transactionId)
        {
            $recordData['transaction_id'] = $transactionId;
        }

        (new ZhunleUserAccountRecord())->UpdateData($uid, $records['id'], $recordData, ['order_id' => $records['order_id']]);
    }
}
